package com.nananren.filter;

import com.alibaba.fastjson.JSON;
import com.nananren.common.MyThreadLocal;
import com.nananren.common.Result;
import com.nananren.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "loginCheckFilter")
public class LoginCheckFilter implements Filter {

    // 路径比较器
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 浏览器第一次发送请求的时候，发送的请求方式是OPTIONS，只有这一次放行了，后面的请求才会通过
        String method = request.getMethod();
        System.out.println("本次请求方式为：" + method);
        if("OPTIONS".equals(method)) {
            filterChain.doFilter(request, response);
            return;
        }


        // 1.获取请求路径
        String requestURI = request.getRequestURI();
        log.info("当前请求路径为：{}", requestURI);

        // 2.定义不需要处理的请求
        String[] urls = new String[]{
                "/employee/login",
                "/user/login",
                "/common"
        };

        // 3.判断requestURI是否在urls中
        boolean flag = check(requestURI, urls);

        // 3.1如果在里面，说明不需要处理，直接放行
        if (flag) {
            log.info("当前请求：{}，不需要处理", requestURI);
            filterChain.doFilter(request, response);
            // 过滤器执行完了还会返回，所以需要return结束方法
            return;
        }

        // 3.2如果不在里面，则判断token
        String token = request.getHeader("Token");

        // 3.2.1 判断token是否为空
        // 如果这里使用isEmpty判断是否为空会导致空指针出现
        if (!StringUtils.hasLength(token)) {
            log.info("请求头为空，返回未登录的错误结果");
            response.getWriter().write(JSON.toJSONString(Result.error("NOT_LOGIN")));
            return;
        }

        // 3.2.2 如果在解析的时候抛异常了，说明令牌非法，需要返回错误结果
        Map<String, Object> claims = null;
        try {
            claims = JwtUtils.parseJwt(token);
        } catch (Exception e) {
            log.info("请求头解析失败，返回未登录的错误结果");
            e.printStackTrace();
            response.getWriter().write(JSON.toJSONString(Result.error("NOT_LOGIN")));
            return;
        }
        // 没有报错，说明令牌合法
        // 将id存入MyThreadLocal中
        log.info("令牌校验合法，放行啦!");
        Long id = (Long) claims.get("id");
        MyThreadLocal.setLocal(id);
        filterChain.doFilter(servletRequest, servletResponse);
    }

    private boolean check(String requestURI, String[] urls) {
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(requestURI, url);
            if (match) {
                return true;
            }
        }
        return false;
    }
}
